package query;

import index.HashIndex;
import global.Minibase;
import global.RID;
import global.SearchKey;
import heap.HeapFile;
import heap.HeapScan;
import parser.AST_Delete;
import relop.Predicate;
import relop.Schema;
import relop.Tuple;

/**
 * Execution plan for deleting tuples.
 */
class Delete implements Plan {
	protected String tableName;
	protected Predicate[][] predicates;
	protected Schema schema;
	protected IndexDesc[] indexes;
  /**
   * Optimizes the plan, given the parsed query.
   * 
   * @throws QueryException if table doesn't exist or predicates are invalid
   */
  public Delete(AST_Delete tree) throws QueryException {
	  tableName = tree.getFileName();
	  // check is table exists
	  QueryCheck.tableExists(tableName);
	  
	  indexes = Minibase.SystemCatalog.getIndexes(tableName);
	  // check if indexes exist
	  for (IndexDesc index : indexes) {
		  QueryCheck.indexExists(index.indexName);
	  }
	  
	  schema = Minibase.SystemCatalog.getSchema(tableName);
	  if (schema == null) throw new QueryException("Invalid table Name");
	  
	  predicates = tree.getPredicates();
	  // check if the predicates exists
	  QueryCheck.predicates(schema, predicates);	  

  } // public Delete(AST_Delete tree) throws QueryException

  /**
   * Executes the plan and prints applicable output.
   */
  public void execute() {
	  int numRows = 0;
	  
	  HeapFile heapFile = new HeapFile(tableName);
	  HeapScan heapScan = heapFile.openScan();
	  
	  while (heapScan.hasNext()) {
		  RID rid = new RID();
		  Tuple tuple = new Tuple(schema, heapScan.getNext(rid));
		  // delete tuple if it matches the predicates
		  if (qualify(tuple)) {
			  // delete indexes for the entry
			  for (IndexDesc index : indexes) {
				  HashIndex hIndex = new HashIndex(index.indexName);
				  Object val = tuple.getField(index.columnName);
			      SearchKey key = new SearchKey(val);
			      hIndex.insertEntry(key, rid);    
			  }
			  // delete entry from file
			  heapFile.deleteRecord(rid);
			  numRows++;
		  }
	  }
	  
    // print the output message
    System.out.println(numRows + " rows affected.");

  } // public void execute()
  
  /**
   * Checks if a tuple qualifies the predicate selection
   * @param tuple
   * @return returns true if the tuple qualifies for the predicates
   */
  private boolean qualify(Tuple tuple) {
	boolean retVal = true;
	
	for (Predicate[] outer : predicates) {
		
		for (Predicate inner : outer) {
			retVal = retVal | inner.evaluate(tuple);
			if (retVal == true) {
				break;
			}
		}
		
		if (retVal == false)
			break;
	}
	
	return retVal;
  }

} // class Delete implements Plan
